package nancal.mp.service.jenkins

import com.offbytwo.jenkins.JenkinsServer
import nancal.mp.db.mongo.JenkinsJobStatusEnum
import nancal.mp.db.mongo.mor
import nbcp.base.comm.ApiResult
import nbcp.base.comm.JsonResult
import nbcp.base.extend.AsInt
import nbcp.base.extend.AsString
import nbcp.base.extend.Important
import nbcp.base.extend.must
import nbcp.base.utils.ReflectUtil
import nbcp.myoql.db.mongo.queryById
import nbcp.myoql.db.mongo.updateById
import org.apache.http.client.HttpResponseException
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import java.net.URI


@Service
class JenkinsService {
    companion object {
        private val logger = LoggerFactory.getLogger(this::class.java.declaringClass)

    }

    fun getJenkinsClient(serverHost: String, username: String, password: String): JenkinsServer {
        if (serverHost.isEmpty()) {
            throw RuntimeException("serverHost不能为空")
        }
        return JenkinsServer(
            URI(serverHost),
            username,
            password
        )
    }


    /**
     * 构建发版流水线
     * @return  会更新 JenkinsLog的 buildNumber, 并返回 buildNumber
     */
    fun buildPublishJob(
        serverHost: String,
        username: String,
        password: String,
        jobId: String
    ): ApiResult<Int> {
        var log =
            mor.dev.jenkinsLog.queryById(jobId).toEntity().must().elseThrow { "找不到构建任务信息" }
        var job = JenkinsPublishJob(log);

        var pipelines = job.getStandardPipeLine();

        var ret = buildJenkinsJob(
            serverHost,
            username,
            password,
            log.buildInfo.serviceName,
            pipelines,
            job.appDeploySetting.jenkinsServer.usePipeline
        )

        if (ret.hasError) {
            return ret;
        }

        if (ret.data.AsInt() <= 0) {
            return ApiResult.error("创建Jenkins任务，没有返回任务号!");
        }

        mor.dev.jenkinsLog.updateById(jobId)
            .set { it.buildInfo.buildNumber to ret.data }
            .set { it.status to JenkinsJobStatusEnum.Created }
            .exec()

        return ret;
    }


    /**
     * 构建 Ops 流水线。
     */
    fun buildOpsExportJob(
        serverHost: String,
        username: String,
        password: String,
        query: JenkinsExportModel,
        usePipeline: Boolean
    ): ApiResult<Int> {

        var job = JenkinsOpsExportJob(query);

        return buildJenkinsJob(
            serverHost,
            username,
            password,
            "k8s-ops-export",
            job.getExportPipeline(),
            usePipeline
        )
    }

//    fun buildOpsImportJob(
//        serverHost: String,
//        username: String,
//        password: String,
//        query: JenkinsImportModel
//    ): ApiResult<Int> {
//
//        var job = JenkinsOpsImportJob(query);
//
//        return buildJenkinsJob(
//            serverHost,
//            username,
//            password,
//            "k8s-ops-import",
//            job.getImportPipeline()
//        )
//    }
    /**
     * https://github.com/cdancy/jenkins-rest
     */
    /**
     * @param credential , 形式： username:password
     * @return 返回Jenkins的buildNumber
     */
    fun buildJenkinsJob(
        serverHost: String,
        username: String,
        password: String,
        jobName: String,
        content: String,
        usePipeline: Boolean,
    ): ApiResult<Int> {
        var jenkinsServer = getJenkinsClient(serverHost, username, password);


        var job = jenkinsServer.getJob(jobName)
        if (job == null) {
            jenkinsServer.createJob(jobName, content, true);
            job = jenkinsServer.getJob(jobName)
        } else {
            //如果存在正在构建的，取消之
            if (job.isInQueue) {
                job.queueItem.isCancelled = true;
            } else if (job.lastBuild.details().isBuilding) {
                job.lastBuild.Stop(true)
            }

            //如果不同，则删之。
            if (usePipeline) {

            }

            try {
                jenkinsServer.updateJob(jobName, content, true)
            } catch (e: Exception) {
                logger.error("更新Jenkins任务时出错", e)
                return ApiResult.error("更新Jenkins Job ${jobName} 失败!");
            }
            job = jenkinsServer.getJob(jobName);
        }

        var buildNumber = job.nextBuildNumber
        logger.Important(
            "jenkins.uri: ${
                ReflectUtil.getValueByWbsPath(job.client, "uri").toString()
            }"
        )
        job.build(true)

//        Thread.sleep(1000);
//        job = jenkinsServer.getJob(jobName);
//        var currentBuildNumber = job.nextBuildNumber - 1;
//
//        if (currentBuildNumber > buildNumber) {
//            buildNumber = currentBuildNumber;
//        }

        logger.Important("任务:${jobName}, buildNumber:${buildNumber}")
        return ApiResult.of(buildNumber)
    }


    fun recordLog(serverHost: String, username: String, password: String, jobId: String) {
        var log =
            mor.dev.jenkinsLog.queryById(jobId).toEntity().must().elseThrow { "找不到任务信息" }


    }

    data class JenkinsLogContentData(
        var buildNumber: Int = 0,
        var content: String = ""
    )

    /**
     *
     * @param buildNumber 获取大于等于 buildNumber 的日志, 获取该日志后,把小于该 buildNumber 的同名Job日志且 status 为Prepare 的置为已过期.
     */
    fun getLog(
        serverHost: String,
        username: String,
        password: String,
        jobName: String,
        buildNumber: Int
    ): ApiResult<JenkinsLogContentData> {
        var jenkinsServer = getJenkinsClient(serverHost, username, password);


        var job = try {
            jenkinsServer.getJob(jobName);
        } catch (ex: HttpResponseException) {
            logger.warn("获取任务出错! ${jobName}, ${ex.statusCode} , ${ex.message}")
            return ApiResult.error(ex.message.AsString("获取任务出错"));
        } catch (ex: Exception) {
            logger.warn("获取任务出错! ${jobName}, ${ex.message}")
            return ApiResult.error(ex.message.AsString("获取任务出错"));
        }

        if (job == null) {
            return ApiResult();
        }
        if (job.isInQueue) {
            return ApiResult();
        }

        var JenkinsLogContentData = JenkinsLogContentData();
        JenkinsLogContentData.buildNumber = job.nextBuildNumber - 1


        if (JenkinsLogContentData.buildNumber == buildNumber || buildNumber <= 0) {
            JenkinsLogContentData.content = job.lastBuild?.details()?.consoleOutputText.AsString()
            ApiResult.of(JenkinsLogContentData)
        }

        if (JenkinsLogContentData.buildNumber < buildNumber) {
            return ApiResult();
        }

        if (JenkinsLogContentData.buildNumber > buildNumber) {
            logger.Important("${jobName}已有最新buildNumber: ${JenkinsLogContentData.buildNumber}")
            return ApiResult.error<JenkinsLogContentData>("已有最新")
                .withValue(JenkinsJobStatusEnum.Expired)
        }


        //兜底
        JenkinsLogContentData.content = job.lastBuild?.details()?.consoleOutputText.AsString()
        return ApiResult.of(JenkinsLogContentData)
    }


    /**
     * 获取日志马上返回.
     */
    fun getLogAtOnce(
        serverHost: String,
        username: String,
        password: String,
        jobName: String
    ): ApiResult<JenkinsLogContentData> {
        var jenkinsServer = getJenkinsClient(serverHost, username, password);

        var JenkinsLogContentData = JenkinsLogContentData();

        var job = try {
            jenkinsServer.getJob(jobName);
        } catch (ex: HttpResponseException) {
            return ApiResult.error("找不到任务");
        } catch (ex: Exception) {
            return ApiResult.error("获取任务出错");
        }

        if (job == null) {
            return ApiResult.error("找不到任务");
        }

        JenkinsLogContentData.buildNumber = job.nextBuildNumber - 1
        if (job.isInQueue) {
            var ret = ApiResult.error<JenkinsLogContentData>("未开始")
            ret.value = JenkinsJobStatusEnum.Prepare
            return ret;
        }

        JenkinsLogContentData.content = job.lastBuild?.details()?.consoleOutputText.AsString()
        return ApiResult.of(JenkinsLogContentData)
    }

    fun delete(
        serverHost: String,
        username: String,
        password: String,
        jobName: String,
    ): JsonResult {
        val jenkinsServer = getJenkinsClient(serverHost, username, password)

        jenkinsServer.getJob(jobName).must().elseThrow { "找不到任务" }
            .also {
                jenkinsServer.deleteJob(jobName, true)
                return JsonResult()
            }
    }


}
